import { axios } from 'taro-axios'
import qs from 'qs'
import { getGlobalData } from '../../configuration/globaldata'
import { getStorageSync, removeStorageSync } from '../../crossplatform/apiservice/storage'
import { reLaunch } from '../../crossplatform/apiservice/navigate'
import pagejumplist from '../../configuration/pagejumplist.json'
import { showToast } from '../../crossplatform/apiservice/toast'
import { getStore } from '../../store/index'
import wxLogin from '../../util/wxLogin'

// store 处理token
class EventEmitter {
  constructor() {
    this._events = {}
  }
  on(eventName, callback) {
    let callbacks = eventName in this._events ? this._events[eventName] : []
    callbacks.push(callback)
    this._events[eventName] = callbacks
  }
  emit(eventName, ...args) {
    const callbacks = this._events[eventName]
    callbacks.map(cb => {
      cb(...args)
    })
  }
  off(eventName, callback) {
    if (!eventName in this._events) return
    let callbacks = this._events[eventName]
    let index = callbacks.indexOf(callback)
    callbacks.splice(index, 1)
  }
}
let DeviceEventEmitter = new EventEmitter()
let accessToken = ''
let userId = ''
let refreshToken = ''

let timer = setTimeout(() => {
  clearTimeout(timer)
  const store = getStore()

  store.subscribe(handleUserInfoChange)
  function handleUserInfoChange() {
    const {
      userinfo: { accessToken: newAccessToken, userId: newUserId, refreshToken: newRefreshToken }
    } = store.getState()
    if (
      userId !== newUserId ||
      accessToken !== newAccessToken ||
      refreshToken !== newRefreshToken
    ) {
      accessToken = newAccessToken
      userId = newUserId
      refreshToken = newRefreshToken
    }
  }
}, 10)
// store 处理token -- over

const globalData = getGlobalData()

const addhost = url => {
  // 添加host 判断url是否有# 有则走App接口 无则走小程序接口
  let indexOf = url.indexOf('@@')
  if (url.indexOf('@@') > -1) {
    return globalData.API_URL + url.substring(indexOf + 2)
  } else {
    return globalData.API_URL + '/mini' + url
  }
}

const jsonToUrlparams = json => {
  if (!json) {
    return ''
  }
  let result = '?'
  for (let attr in json) {
    result += `${attr}=${json[attr] || json[attr] === false ? encodeURIComponent(json[attr]) : ''}&`
  }
  return result.substring(0, result.length - 1)
}

export const wechatrequest = {
  // 对taro请求进行一次封装
  get(url, options) {
    if (!options) {
      options = {}
    }
    options.params = options.data
    options.method = 'GET'
    return request(url, options)
  },
  post(url, options, headers) {
    if (!options) {
      options = {}
    }
    if (!options.headers) {
      options.headers = {}
    }
    options.method = 'POST'
    options.headers['content-type'] = 'application/json'
    options.headers = { ...options.headers, ...headers }
    return request(url, options)
  },
  postform(url, options, headers) {
    if (!options) {
      options = {}
    }
    if (!options.headers) {
      options.headers = {}
    }
    options.data = qs.stringify(options.data)
    options.method = 'POST'
    options.headers['content-type'] = 'application/x-www-form-urlencoded;charset=utf-8'
    options.headers = { ...options.headers, ...headers }
    return request(url, options)
  },
  postbody(url, options) {
    if (!options) {
      options = {}
    }
    if (!options.headers) {
      options.headers = {}
    }
    options.method = 'POST'
    options.headers['content-type'] = 'application/json'
    return request(url, options)
  },
  postparams(url, options, token = false) {
    if (!options) {
      options = {}
    }
    if (!options.headers) {
      options.headers = {}
    }
    options.method = 'POST'
    options.headers['content-type'] = 'application/x-www-form-urlencoded;charset=utf-8'
    url += jsonToUrlparams(options.data)
    options.data = {}
    return request(url, options, token)
  },
  put(url, options) {
    if (!options) {
      options = {}
    }
    if (!options.headers) {
      options.headers = {}
    }
    options.method = 'PUT'
    options.headers['content-type'] = 'application/json'
    url += jsonToUrlparams(options.data)
    options.data = {}
    console.log(options, url)
    return request(url, options)
  },
  putJson(url, options) {
    if (!options) {
      options = {}
    }
    if (!options.headers) {
      options.headers = {}
    }
    options.method = 'PUT'
    options.headers['content-type'] = 'application/json'
    return request(url, options)
  },
  delete(url, options) {
    if (!options) {
      options = {}
    }
    if (!options.headers) {
      options.headers = {}
    }
    options.method = 'DELETE'
    options.headers['content-type'] = 'application/json'
    url += jsonToUrlparams(options.data)
    options.data = {}
    return request(url, options)
  },
  deleteJson(url, options) {
    if (!options) {
      options = {}
    }
    if (!options.headers) {
      options.headers = {}
    }
    options.method = 'DELETE'
    options.headers['content-type'] = 'application/json'
    return request(url, options)
  }
}

export function request(url, options, token = false) {
  // 添加host globaldata里面去取host
  const re = /(http|https):\/\//
  const urlformat = re.test(url) ? url : addhost(url)

  if (!options) {
    // 默认为{}
    options = {}
  }
  if (!options.headers) {
    // 默认header
    options.headers = {}
  }
  if (!options.method) {
    // 默认method
    options.method = 'GET'
  }
  if (!options.headers['content-type']) {
    // 默认content-type
    options.headers['content-type'] = 'application/json'
  }
  const userinfo = getStorageSync('userinfo') || {}
  if (userinfo.openId) options.headers['openId'] = userinfo.openId
  if (userinfo.userId) options.headers['userId'] = userinfo.userId
  if (userinfo.companyId) options.headers['companyId'] = userinfo.companyId
  options.headers['Authorization'] = !token
    ? 'Bearer ' + userinfo.accessToken
    : 'Basic emhpY2h1LW1pbmk6emhpY2h1'
  return new Promise(resolve => {
    axios({
      url: urlformat,
      ...options
    })
      .then(res => {
        resolve(res)
      })
      .catch(() => {
        resolve({ data: { networkerror: false } })
      })
  })
}

let isRefreshTokening = false
// 请求拦截处理
axios.interceptors.request.use(
  config => {
    // 在发送请求之前做些什么
    if (accessToken && !config.headers.Authorization) {
      config.headers.Authorization = `Bearer ${accessToken}`
    }
    return config
  },
  error => {
    // 对请求错误做些什么
    return Promise.reject(error)
  }
)

// 接口返回拦截处理
axios.interceptors.response.use(
  response => {
    // 对响应数据做点什么
    if (!response.data) {
      return Promise.reject(new Error('响应内容为空'))
    }
    const { code } = response.data
    if (code === 401 && (isRefreshTokening || refreshToken)) {
      if (response.config.url.indexOf('auth/token') !== -1) {
        return
      }
      const oldToken = accessToken
      if (!isRefreshTokening) {
        isRefreshTokening = true
        console.log('store.dispatch(DO_REQUEST_AUTH_TOKEN_ACTION) --->begin')

        // 去刷新token
        wxLogin.refreshToken(refreshToken).then(({ accessToken, refreshToken }) => {
          console.log('store.dispatch(DO_REQUEST_AUTH_TOKEN_ACTION) --->end')
          isRefreshTokening = false
          DeviceEventEmitter.emit('REFRESHTOKENING')
        })
      }
      // 正在刷新token中
      console.log(
        'DeviceEventEmitter.addListener(REFRESHTOKENING) --->subscription',
        response.config.url
      )
      DeviceEventEmitter.on('REFRESHTOKENING', () => {
        console.log(
          'DeviceEventEmitter.addListener(REFRESHTOKENING) --->unsubscription',
          response.config.url
        )
        if (!isRefreshTokening) {
          DeviceEventEmitter.off('REFRESHTOKENING')
        }
        if (accessToken && oldToken !== accessToken) {
          const config = response.config
          config.headers.Authorization = ''
          return axios(config)
        } else {
          showToast({
            title: '请重新登录'
          })
          let timer = setTimeout(() => {
            clearTimeout(timer)
            // removeStorageSync('userinfo')
            reLaunch({ url: `${pagejumplist['start-page'].path}` })
          }, 500)
          return Promise.reject(new Error(response.data.message))
        }
      })
    } else {
      return response
    }
  },
  error => {
    // 对响应错误做点什么
    if (!error.response) {
      showToast({
        title: '网络走丢了～'
      })
    }
    console.warn('网络请求失败', error)
    return Promise.reject(error)
  }
)
